/********************************************************************************
* Description: event basic service, provides thread inter-connection and manages threads,
it simply executes tasks without caring about business logic. all messages are encapsulated
as commands and queued for asynchronous processing,
* Author: hsqiang
* Create Date: 2023-06-17
********************************************************************************/
#ifndef EVENT_LOOP_HPP_
#define EVENT_LOOP_HPP_

#include "poller.hpp"
#include "command_queue.hpp"
#include "timer_queue.hpp"
#include "awakener.hpp"
#include "noncopyable.hpp"
#include "assert_define.hpp"
#include <functional>
#include <memory>
#include <atomic>

namespace event_framework
{
    using Command = std::function<void()>;
    using Callback = std::function<void()>;
    using RetCommand = std::function<int()>;
    using CallbackRet = std::function<void(int)>;
    class EventLoop;
    class EventLoop final : Noncopyable
    {
    public:
        EventLoop() : awakener(*this), timerQue(*this) {}
        ~EventLoop() = default;
        bool Init();
        /********************************************************************************
        * Description: normal command, execute right now
        ********************************************************************************/
        void Accept(Command&& cmd)
        {
            ASSERT(cmd);
            cmdQue.Accept(std::move(cmd));
            Wakeup();
        }
        /********************************************************************************
        * Description: timer conmand, execute at 'after' and periodly
        ********************************************************************************/
        void Accept(Timestamp after, Timestamp period, Command&& cmd)
        {
            ASSERT(cmd);
            timerQue.Accept(after, period, std::move(cmd));
            Wakeup();
        }
        /********************************************************************************
        * Description: add <request> into <other> loop, and await <callback> be called in this loop
        ********************************************************************************/
       void Loopback(EventLoop& other, Command&& request, Callback&& callback);
       void Loopback(EventLoop& other, RetCommand&& request, CallbackRet&& callback);
        // includes add/mod/del operation
        bool UpdateChannel(ChannelPtr ch)
        {
            poller.UpdateChannel(ch);
        }
        // you should execute Loop() in another thread, or the current thread will be blocked
        void Loop();
        // stop event oop
        void Break() { quit = true; Wakeup(); }
    private:
        void Wakeup() { awakener.Wakeup(); }
        void Poll();
        void HandleCommands();
        
        std::atomic_bool quit { false };
        Poller poller;
        Awakener awakener;
        TimerQueue<Command> timerQue;
        CommandQueue<Command> cmdQue;
    };
    using EventLoopPtr = std::unique_ptr<EventLoop>;
}

#endif